use askama::Template;
use axum::extract::Query;
use axum::http::StatusCode;
use axum::{extract::State, Form};
use axum_session::{Session, SessionRedisPool};
use headers::HeaderMap;
use serde::Deserialize;

use crate::stores::sql;
use crate::{
    handlers::{log_error, render, HtmlView},
    stores::redisx,
    Result, SharedState, UserSession, SESSION_KEY,
};

use super::EcodeParams;

#[derive(Debug, Template)]
#[template(path = "frontend/login.html")]
pub struct LoginTemplate<'a> {
    pub err: &'a str,
}

pub async fn login_html(params: Query<EcodeParams>) -> Result<HtmlView> {
    tracing::debug!("the params {:?}", params);
    let err_code = params.ecode.unwrap_or(10000);
    let err = match err_code {
        10000 => "",
        10001 => "验证码不能为空",
        10002 => "验证码不正确",
        _ => "未知错误",
    };
    let handler_name = "frontend/login/login";
    let tmpl = LoginTemplate { err };
    tracing::debug!("the tmpl {:?}", tmpl);
    render(tmpl).map_err(log_error(handler_name))
}

#[derive(Deserialize)]
pub struct Login {
    pub vcode: String,
}

pub async fn login_action(
    session: Session<SessionRedisPool>,
    State(state): State<SharedState>,
    Form(l): Form<Login>,
) -> Result<(StatusCode, HeaderMap, ())> {
    tracing::debug!("code {}", l.vcode);

    let rs = &state.rs;
    let vcode = format!("vcode-{}", l.vcode);
    let openid = redisx::get(rs, &vcode).await.unwrap_or("".to_string());
    tracing::debug!("openid {}", openid);
    let mut headers = HeaderMap::new();
    let mut url = String::new();
    if openid != "" {
        tracing::debug!("Login success");
        let db = &state.db;
        let user = sql::query_user(db, openid.clone()).await?;
        let user_session = UserSession {
            openid: openid.clone(),
            name: user.nickname,
        };
        session.set(SESSION_KEY, user_session);

        let _ = redisx::del(rs, &vcode).await?;
        url.push_str("/listbook?page=1&page_size=5");
    } else {
        let ecode;
        if l.vcode == "" {
            ecode = 10001;
        } else {
            ecode = 10002;
        }
        let lurl = format!("/login?ecode={}", ecode);
        url.push_str(&lurl);
    }

    headers.insert(axum::http::header::LOCATION, url.parse().unwrap());
    Ok((StatusCode::FOUND, headers, ()))
}
